package org.abc.fund.config.exception;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.abc.fund.util.exception.ResourceNotFoundException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

/** 全局REST异常处理器类，用于处理控制器中抛出的异常 */
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {

  /**
   * 处理资源未找到异常的方法 当抛出ResourceNotFoundException时调用此方法
   *
   * @param ex 资源未找到异常
   * @param request Web请求对象
   * @return 返回包含错误信息的HTTP响应实体
   */
  @ExceptionHandler(value = {ResourceNotFoundException.class})
  protected ResponseEntity<Object> handleResourceNotFound(
      ResourceNotFoundException ex, WebRequest request) {
    // 使用异常消息作为响应体
    String bodyOfResponse = ex.getMessage();
    // 调用内部方法处理异常，返回HTTP 404状态
    return handleExceptionInternal(
        ex, bodyOfResponse, new HttpHeaders(), HttpStatus.NOT_FOUND, request);
  }

  /**
   * 处理非法参数异常的方法
   *
   * @param ex 非法参数异常
   * @param request Web请求对象
   * @return 返回包含错误信息的HTTP响应实体
   */
  @ExceptionHandler(value = {IllegalArgumentException.class, IllegalStateException.class})
  protected ResponseEntity<Object> handleIllegalArgument(
      IllegalArgumentException ex, WebRequest request) {
    // 构造响应体，包含参数无效的信息
    String bodyOfResponse = "Invalid request parameter: " + ex.getMessage();
    // 调用内部方法处理异常，返回HTTP 400状态
    return handleExceptionInternal(
        ex, bodyOfResponse, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
  }

  /**
   * 处理方法参数验证不合法异常的方法 当方法参数验证失败时调用此方法
   *
   * @param ex 方法参数验证不合法异常
   * @param headers HTTP响应头
   * @param status HTTP状态码
   * @param request Web请求对象
   * @return 返回包含验证错误信息的HTTP响应实体
   */
  @Override
  protected ResponseEntity<Object> handleMethodArgumentNotValid(
      MethodArgumentNotValidException ex,
      @SuppressWarnings("NullableProblems") HttpHeaders headers,
      HttpStatusCode status,
      @SuppressWarnings("NullableProblems") WebRequest request) {
    // 创建错误信息映射
    Map<String, String> errors = new HashMap<>();
    // 遍历所有验证错误，提取字段名和错误消息
    ex.getBindingResult()
        .getAllErrors()
        .forEach(
            (error) -> {
              String fieldName = ((FieldError) error).getField();
              String errorMessage = error.getDefaultMessage();
              errors.put(fieldName, errorMessage);
            });

    // 构造响应体，包含时间戳、状态码和错误信息
    Map<String, Object> body = new HashMap<>();
    body.put("timestamp", new Date());
    body.put("status", status.value());
    body.put("errors", errors);

    // 返回包含错误信息的HTTP响应实体
    return new ResponseEntity<>(body, headers, status);
  }
}
